package com.xhz.cas.adaptors.generic;

import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.google.common.collect.Lists;
import com.xhz.cas.model.entity.SsoUser;
import com.xhz.cas.model.service.SsoUserService;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.apereo.cas.authentication.*;
import org.apereo.cas.authentication.exceptions.AccountDisabledException;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.security.auth.login.AccountLockedException;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Shiro身份验证处理程序
 * @author huangcb on 2020/4/26
 */
public class ShiroAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {

    @Autowired
    @Qualifier("ssoUserServiceImpl")
    private SsoUserService ssoUserService;

    private static final Logger logger = LoggerFactory.getLogger(ShiroAuthenticationHandler.class);

    public ShiroAuthenticationHandler(String name,ServicesManager servicesManager,PrincipalFactory principalFactory,Integer order) {
        super(name, servicesManager, principalFactory, order);
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential transformedCredential,String originalPassword) throws GeneralSecurityException {

        try {
            UsernamePasswordToken token = new UsernamePasswordToken(transformedCredential.getUsername(),transformedCredential.getPassword());

            if (transformedCredential instanceof RememberMeUsernamePasswordCredential) {
                token.setRememberMe(RememberMeUsernamePasswordCredential.class.cast(transformedCredential).isRememberMe());
            }

            Subject currentUser = getCurrentExecutingSubject();
            currentUser.login(token);
            String username = String.valueOf(currentUser.getPrincipal());
            SsoUser ssoUser = ssoUserService.getByLoginInfo(username);
//            boolean hasRole = currentUser.hasRole("ROLE_ADMIN");
            if (ssoUser.getDisabled() == 1) {
                throw new LockedAccountException("账号已被锁定,请联系管理员！");
            }
            if (ssoUser.getExpired() == 1) {
                throw new LockedAccountException("账号已过期,请联系管理员！");
            }
            Map<String, Object> returnInfo = BeanUtils.beanToMap(ssoUser);
            returnInfo.put("password",null);
            final List<MessageDescriptor> list = new ArrayList<>();
            return createHandlerResult(transformedCredential, this.principalFactory.createPrincipal(currentUser.getPrincipal().toString(), returnInfo),list);
//            return createAuthenticatedSubjectResult(transformedCredential, currentUser);
        } catch (final UnknownAccountException uae) {
            throw new AccountNotFoundException(uae.getMessage());
        } catch (final IncorrectCredentialsException ice) {
            throw new FailedLoginException(ice.getMessage());
        } catch (final LockedAccountException | ExcessiveAttemptsException lae) {
            throw new AccountLockedException(lae.getMessage());
        } catch (final ExpiredCredentialsException eae) {
            throw new CredentialExpiredException(eae.getMessage());
        } catch (final DisabledAccountException eae) {
            throw new AccountDisabledException(eae.getMessage());
        } catch (final AuthenticationException e) {
            throw new FailedLoginException(e.getMessage());
        }
    }


    /**
     * Create authenticated subject result.
     *
     * @param credential  the credential
     * @param currentUser the current user
     * @return the handler result
     */
    protected AuthenticationHandlerExecutionResult createAuthenticatedSubjectResult(final Credential credential, final Subject currentUser) {
        final String username = currentUser.getPrincipal().toString();
        return createHandlerResult(credential, this.principalFactory.createPrincipal(username));
    }

    /**
     * Gets current executing subject.
     *
     * @return the current executing subject
     */
    protected Subject getCurrentExecutingSubject() {
        return SecurityUtils.getSubject();
    }
}
